package dungeonElements;

import be.kuleuven.cs.som.annotate.Raw;
import dungeonTools.Direction;
import temperature.Temperature;

/**
 * A class of normal squares. A NormalSquare is a TeleportationSquare with more constraints 
 * for the borders.
 * 
 * @invar A NormalSquare has always proper borders. This means:
 * 		-a NormalSquare has a border in at least one direction
 * 		-a NormalSquare has at most 3 doors
 * 		-a NormalSquare has no doors in the floor
 * 		|hasProperBorders()
 * 
 * 
 * @author Tom Jacobs & Ewoud De Moor
 * @version 3.0
 */
public class NormalSquare extends TeleportationSquare {

	/**
	 * Creates a new normal square with the following attributes:
	 * Temperature - see param temperature
	 * Humidity - see param humidity
	 * Borders - see param northBorder, eastBorder, southBorder, 
	 * 						westBorder, ceilingBorder and floorBorder
	 * Slippery Surface - DEFAULT: false
	 * Terminated - DEFAULT: false
	 * 
	 * @param temperature
	 * 		The temperature this normal square will have.
	 * @param humidity
	 * 		The humidity level this normal square will have.
	 * @param northBorder
	 * 		Determines whether this normal square has a wall in the northern direction.
	 * @param eastBorder
	 * 		Determines whether this normal square has a wall in the eastern direction.
	 * @param southBorder
	 * 		Determines whether this normal square has a wall in the southern direction.
	 * @param westBorder
	 * 		Determines whether this normal square has a wall in the western direction.
	 * @param ceilingBorder
	 * 		Determines whether this normal square has a wall in the ceiling.
	 * @param floorBorder
	 * 		Determines whether this normal square has a wall in the floor.
	 * @effect This new normal square is initialized as a TeleportationSquare with the 
	 * 		attributes defined above.
	 * 		| super(temperature, humidity, northBorder, eastBorder, southBorder, 
	 * 		|			westBorder, ceilingBorder, floorBorder)
	 */
	@Raw
	public NormalSquare(Temperature temperature, double humidity, 
			boolean northBorder, boolean eastBorder, boolean southBorder, 
			boolean westBorder, boolean ceilingBorder, boolean floorBorder) {
		super(temperature, humidity, northBorder, eastBorder, southBorder, 
				westBorder, ceilingBorder, floorBorder);
	}
	
	/**
	 * Creates a new default normal square with the following attributes:
	 * Temperature - the DEFAULT_TEMPERATURE value
	 * Humidity - the Temperature.DEFAULT_HUMIDITY value
	 * Borders - DEFAULT: Walls in all directions
	 * Slippery Surface - DEFAULT: false
	 * Terminated - DEFAULT: false
	 * 
	 * @effect This new normal square is initialized as a default TeleportationSquare.
	 * 		| super()
	 */ 
	@Raw
	public NormalSquare() {
		super();
	}
	
	
	/**
	 * Check whether this NormalSquare can have the given border in the given direction 
	 * as its border.
	 * 
	 * @param border
	 * 		The border to check
	 * @param direction
	 * 		The direction to check
	 * @return False if direction is not initialized
	 * 		| if(direction == null)
	 * 		|	then result == false
	 * @return True if this NormalSquare is terminated and the border is set to nothing.
	 * 		| if(this.isTerminated && (border==null))
	 * 		|	then result == true
	 * @return False if the given border is a terminated border
	 * 		| if( (border!=null) && border.isTerminated())
	 * 		|	then result == false
	 * @return True if setting the border wouldn't change anything.
	 * 		| if( (getBorder(direction) != null && getBorder(direction).equals(border))
	 *		|		|| ((getBorder(direction)==null)&&(border==null)) )
	 * 		|	then result == true
	 * @return False if a TeleportationSquare can't have the given border in the given direction.
	 * 		| if(!super.canHaveAsBorderInDirection(border, direction))
	 * 		|	then result == false
	 * @return False if adding the border would result in a NormalSquare with a door 
	 * 		in the floor.
	 * 		| if( (border instanceof Door) && (direction==Direction.FLOOR) )
	 * 		|	then result == false
	 * @return False if setting the border in the given direction would result 
	 * 		in a NormalSquare without borders.
	 * 		| for each directionInDirection in Direction:
	 * 		|	if(hasBorderInDirection(directionInDirection))
	 * 		|		countBorders++
	 * 		| if( (countBorders==0) && (border==null) )
	 * 		| 	then result == false
	 * 		| if( (countBorders==1) && (border==null) && (hasBorderInDirection(direction)) )
	 * 		| 	then result == false
	 * @return False if setting the border would result in a NormalSquare with more 
	 * 		than 3 doors.
	 * 		| for each directionInDirection in Direction:
	 * 		|	if(getBorder(directionInDirection) instanceof Door))
	 * 		|		countDoors++
	 * 		| if(countDoors > 4)
	 * 		| 	then result == false
	 * 		| else if( (countDoors == 4)&&(border instanceof Door) )
	 * 		| 	then result == false
	 * 		| else if( (countDoors == 4)&&(!(border instanceof Door))
	 * 		|			&&!(getBorder(direction) instanceof Door) )
	 * 		| 	then result == false
	 * 		| else if( (countDoors==3)&&(border instanceof Door)
	 * 		|			&&!(getBorder(direction) instanceof Door) ) 
	 * 		| 	then result == false
	 */
	@Override @Raw
	public boolean canHaveAsBorderInDirection(@Raw Border border, Direction direction){
		if(direction == null)
			return false; //Direction not initialized
		if( this.isTerminated() && (border==null) )
			return true;
		if( (border!=null) && border.isTerminated())
			return false; //Can not have a terminated border
		if( (getBorder(direction) != null && getBorder(direction).equals(border))
				|| ((getBorder(direction)==null)&&(border==null)) )
			return true; //Current state
		
		if(!super.canHaveAsBorderInDirection(border, direction))
			return false; //Needed to check for doors between squares of a shaft
		
		if( (border instanceof Door) && (direction==Direction.FLOOR) )
			return false; //No door in floor
		int countBorders = 0;
		int countDoors = 0;
		for(Direction allDirections : Direction.values()){
			//Count borders and doors
			if(hasBorderInDirection(allDirections)){
				countBorders++;
				if( getBorder(allDirections) instanceof Door )
					countDoors++;
			}
		}
		if( (countBorders<=1) && (border==null) ) {
			if(countBorders==0)
				return false; //Would result in no borders
			if( hasBorderInDirection(direction) )
				return false; //Would result in no borders
		}
		if( countDoors>=3 ){
			if( countDoors>4 )
				return false; //Too many doors
			if( (countDoors==3) && (border instanceof Door) 
					&& !(getBorder(direction) instanceof Door) )
				return false; //Too many doors
			if( (countDoors==4) && !(border instanceof Door) 
					&& !(getBorder(direction) instanceof Door) ){
				return false; //Too many doors
			}
		}
		return true;
	}
	
	/**
	 * Check whether this NormalSquare has proper borders.
	 * 
	 * @return False if this TeleportaionSquare hasn't proper borders
	 * 		| if(!super.hasProperBorders())
	 * 		|	then result == false
	 * @return False if this NormalSquare has no borders.
	 * 		| for each direction in Direction:
	 * 		|	if(hasBorderInDirection(direction))
	 * 		|		countBorders++
	 * 		| if(countBorders >= 1)
	 * 		| 	then result == false
	 * @return False if this NormalSquare has more than 3 doors.
	 * 		| for each direction in Direction:
	 * 		|	if(getBorder(direction) instanceof Door))
	 * 		|		countDoors++
	 * 		| if(countDoors > 3)
	 * 		| 	then result == false
	 * @return False if this NormalSquare has a doors in the floor.
	 * 		| if(getBorder(Direction.FLOOR) instanceof Door)
	 * 		|	then result == false
	 */
	@Override @Raw
	public boolean hasProperBorders(){
		if(!super.hasProperBorders())
			return false;
		int countBorders = 0;
		int countDoors = 0;
		for(Direction allDirections : Direction.values()){
			//Count borders and doors
			if(hasBorderInDirection(allDirections)){
				countBorders++;
				if( getBorder(allDirections) instanceof Door )
					countDoors++;
			}
		}
		//Check counters
		if(countBorders < 1)
			return false;
		if(countDoors > 3)
			return false;		
		//Check door in floor
		if(getBorder(Direction.FLOOR) instanceof Door)
			return false;
		return true;	
	}
}
